﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting;
using MessageCallAspect.Inspector.MessageSink;

namespace MessageCallAspect.Inspector
{
    public static class MessageCallAspectExtensions
    {
        public static T InspectorProxy<T>(this T target)
             where T : class
        {
            return target.InspectorProxy();
        }
        public static T InspectorProxy<T>(this T target, IModuleContext context)
             where T : class
        {
            return target.InspectorProxy(context);
        }
        public static T InspectorProxy<T>(this T target, IModuleContext context, params IMessageSinkCreator[] dynamicMessageSinkCreator)
            where T : class
        {
            return (T)new TargetInspectorProxy<T>(target, context, dynamicMessageSinkCreator).GetTransparentProxy();
        }
    }
    public static class ReflectionExtensions
    {
        public static T[] GetAllAttributes<T>(this ICustomAttributeProvider member)
          where T : Attribute
        {
            return member.GetCustomAttributes(typeof(T), true) as T[];
        }
        public static bool HasAttribute<T>(this ICustomAttributeProvider member)
            where T : Attribute
        {
            return member.IsDefined(typeof(T), true);
        }
    }

    public static class MessagingExtensions
    {
        public static void ValidateParameters(this IMessage msg)
        {
            IMethodCallMessage mcm = (IMethodCallMessage)msg;

            MethodInfo mi = (MethodInfo)mcm.MethodBase;

            ParameterInfo[] parameters = mi.GetParameters();
            int narg = 0;

            foreach (ParameterInfo pi in parameters)
            {
                object pval = mcm.GetArg(narg++);
                Type pt = pi.ParameterType;
                if (pt.IsByRef) pt = pt.GetElementType();

                if (pval != null && !pt.IsInstanceOfType(pval))
                    throw new RemotingException("Cannot cast argument " + pi.Position + " of type '" + pval.GetType().AssemblyQualifiedName +
                            "' to type '" + pt.AssemblyQualifiedName + "'");
            }
        }

        public static ReturnMessage Wrap(this Exception ex, IMessage msg)
        {
            if ((ex is RemotingException || ex is TargetInvocationException)
                  && ex.InnerException != null)
                ex = ex.InnerException;
            return new ReturnMessage(ex, (IMethodCallMessage)msg);
        }
    }
}
